import { IParams, IRequestData, IRequestParams } from "./request";
import { CONTENT_TYPE, ERROR, HEADER, METHOD, RESPONSE_TYPE } from "./config";
import { downloadFile, request, uploadFile } from "@tarojs/taro";

export type {
    IParams, IRequestData, IRequestParams
}

class RequestData implements IRequestData {
    private readonly requestParams: IParams;
    private requestInstance: any

    private executeRequest<T>(url: string, requestBody?: object): Promise<T> {
        this.requestParams.url = url;
        if (requestBody) this.requestParams.requestBody = requestBody;
        return requestData<T>(this.requestParams);
    }

    constructor() {
        this.requestParams = {
            method: METHOD.Get,
            url: "",
            requestBody: undefined,
            headers: [],
            async: true,
            responseType: RESPONSE_TYPE.Json,
        }
    }

    static Header = HEADER
    static ContentType = CONTENT_TYPE
    static ResponseType = RESPONSE_TYPE
    static Method = METHOD
    static Error = ERROR

    async get<T>(url: string, requestBody?: object):
        Promise<T> {
        this.requestParams.method = METHOD.Get;
        return this.executeRequest<T>(url, requestBody)
    }

    async post<T>(url: string, requestBody?: object):
        Promise<T> {
        this.requestParams.method = METHOD.Post;
        return this.executeRequest<T>(url, requestBody)
    }

    async delete<T>(url: string, requestBody?: object): Promise<T> {
        this.requestParams.method = METHOD.Delete;
        return this.executeRequest<T>(url, requestBody)
    }

    async put<T>(url: string, requestBody?: object): Promise<T> {
        this.requestParams.method = METHOD.Put;
        return this.executeRequest<T>(url, requestBody)
    }

    async uploadFile(url: string, filePath: string, name?: string, formData?: object) {
        this.requestParams.url = url;
        return request_uploadFile(this.requestParams, filePath, name, formData);
    }

    async downloadFile(url: string) {
        this.requestParams.url = url;
        return request_downloadFile(this.requestParams);
    }

    abortRequest() {
        if (this.requestInstance) this.requestInstance.abort();
        else console.error('abortRequest()', '未获取到请求实例')
    }

    handleAbort(callback: () => void) {
        callback();
    }

    setHeader(name: string, value: string) {
        const index = this.requestParams.headers.findIndex(m => m.name === name);
        if (index >= 0) this.requestParams.headers[index].value = value;
        else this.requestParams.headers.push({ name, value });
    }

    setHeaderBearer(value: string) {
        const name = HEADER.Authorization;
        const data = `Bearer ${value}`;
        const index = this.requestParams.headers.findIndex(m => m.name === name);
        if (index >= 0) this.requestParams.headers[index].value = data;
        else this.requestParams.headers.push({ name, value: data });

    }

    setHeaderBasic(value: string) {
        const name = HEADER.Authorization;
        const data = `Basic ${value}`;
        const index = this.requestParams.headers.findIndex(m => m.name === name);
        if (index >= 0) this.requestParams.headers[index].value = data;
        else this.requestParams.headers.push({ name, value: data });
    }

    setAsync(value: boolean) {
        this.requestParams.async = value;
    }

    setTimeout(time: number) {
        this.requestParams.timeout = time;
    }

    setResponseType(responseType: XMLHttpRequestResponseType) {
        this.requestParams.responseType = responseType;
    }

    setRequest(request: any) {
        this.requestParams.request = request;
    }
}

/**
 * 请求封装
 * @param params          请求参数
 */
const requestData = function <T>(params: IParams): Promise<T> {
    return new Promise((resolve, reject) => {
        try {
            // 使用 reduce 构建 header
            const header = params.headers?.reduce((acc, item) => {
                acc[item.name] = item.value;
                return acc;
            }, {} as Record<string, string>) || {};

            request({
                url: params.url,
                method: params.method as any,
                header,
                data: params.requestBody,
                success: (res) => {
                    if (res.statusCode === 200) {
                        resolve(res.data);
                    } else {
                        reject(res);
                    }
                },
                fail: (err) => {
                    console.error('Request failed:', err);
                    reject(new Error(`Request failed: ${err.errMsg}`));
                }
            });
        } catch (error) {
            console.error('Request initialization failed:', error);
            reject(new Error(`Request initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
        }
    });
}

const request_uploadFile = function (params: IParams, filePath: string, name?: string, formData?: object) {
    return new Promise((resolve, reject) => {
        try {
            // 使用 reduce 构建 header
            const header = params.headers.reduce((acc, item) => {
                acc[item.name] = item.value;
                return acc;
            }, {} as Record<string, string>);

            uploadFile({
                url: params.url,
                header,
                filePath,
                name: name ?? 'file',
                formData,
                success: (files) => {
                    if (files.statusCode === 200 || files.statusCode === 204) {
                        resolve(files.data);
                    } else {
                        reject(new Error(`Upload failed with status code ${files.statusCode}`));
                    }
                },
                fail: (err) => {
                    reject(new Error(`Upload failed: ${err.errMsg}`));
                }
            });
        } catch (error) {
            reject(new Error(`Upload initialization failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
        }
    });
}


const request_downloadFile = function (params: IParams) {
    return new Promise((resolve, reject) => {
        downloadFile({
            url: params.url,
            success: (files) => {
                if (files.statusCode === 200) resolve(files.tempFilePath)
                else reject(files)
            }
        })
    })
}


export default RequestData
